﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;

namespace SimpleCADControl.GeoObjects
{





    //////////////////////////////////////////////////// Basisklasse /////////////////////////////////////////////////////////
    /// <summary>
    /// Abstrakte Klasse für das GeoObject
    /// </summary>
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public abstract class GeoObject
    {

        /// <summary>
        /// Draw - Methode zum Zeichnen
        /// </summary>
        /// <param name="g">Graphics  Object</param>
        /// <param name="translation">Verschiebung</param>
        public virtual void Draw(Graphics g)
        {
            if (IsMoving)
            {
                g.DrawLine(Pens.Green, (Point)Parent.MouseStartPoint, (Point)(MovePoint * Parent.TranslationScaleMatrix));
            }
            if (Parent.EditMode == CADControl.CADEditMode.Cut)
            {

                g.DrawLine(Pens.Black, (Point)Parent.MouseStartPoint, (Point)Parent.CurrentMouseCoordinates);
                Parent.Invalidate(true);

            }
            if (ShowLabel)
            {
                try
                {
                    Vector2D point = MovePoint * Parent.TranslationScaleMatrix;
                    SizeF stringSize = g.MeasureString(Label, new Font("Arial Black", 12));
                    Size scrollbarSize = Parent.PictureBox.Size - Parent.PictureBox.ClientSize;
                    if (point.X + stringSize.Width > Parent.PictureBox.Width - scrollbarSize.Width)
                    {
                        point.X -= stringSize.Width;
                    }
                    if (point.Y + stringSize.Height > Parent.PictureBox.Height - scrollbarSize.Height)
                    {
                        point.Y -= stringSize.Height;
                    }

                    g.DrawString(Label, new Font("Arial Black", 12), new SolidBrush(Color.Black), point);

                }
                catch
                {
                    //System.Windows.Forms.MessageBox.Show(ex.Message);
                }
            }
        }

        Timer flashTimer = new Timer();
        private int ticks = 0;
        private bool flash = false;
        public bool Flash
        {
            set
            {
                flash = value;
                if (value)
                {
                    flashTimer.Interval = 500;
                    ticks = 0;
                    flashTimer.Start();
                }
                else
                {
                    flashTimer.Stop();
                    ticks = 0;
                }
            }
            get
            {
                return flash;
            }
        }

        void t_Tick(object sender, EventArgs e)
        {
            this.DrawingColor = this.DrawingColor.Complement();
            Parent.Invalidate(true);
            if (ticks++ == 5)
            {
                (sender as Timer).Stop();
                ticks = 0;
                Flash = false;
            }
        }

        /// <summary>
        /// Move - Methode zum Bewegen eines GeoObjects
        /// </summary>
        public virtual void Move()
        {

        }

        /// <summary>
        /// Abstrakte Methode Edit zum Editieren von einzelnen Punkten
        /// </summary>
        /// <param name="pointToEdit">der zu editierende Punkt</param>
        public abstract void Edit(int pointToEdit);

        /// <summary>
        /// Abstrakte Methode zum Kopieren eines Objekts
        /// </summary>
        /// <returns>Objekt - Kopie</returns>
        public abstract GeoObject Clone();

        /// <summary>
        /// Öffnet das Kontextmenu für Objekte an einer bestimmten Stelle
        /// </summary>
        /// <param name="coord">Koordinaten, an denen Menu angezeigt wird</param>
        public void OpenContextMenu(Point coord)
        {
            ObjectSpecificMenu.Show(Parent, coord);
        }

        private String status;
        /// <summary>
        /// Speichert einen Status über das Objekt ab
        /// </summary>
        public String Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
            }
        }

        private String info;
        /// <summary>
        /// Speichert Informationen über das Objekt ab
        /// </summary>
        public String Info
        {
            get
            {
                return info;
            }
            set
            {
                info = value;
            }
        }
        private String label;
        /// <summary>
        /// ein Label für das GeoObject
        /// </summary>
        [System.ComponentModel.Description("Label des GeoObjects"),
        System.ComponentModel.Category("GeoObject")]
        public String Label
        {
            get
            {
                return label;
            }
            set
            {
                label = value;
            }
        }

        private bool showLabel;
        [System.ComponentModel.Description("Gibt an, ob Label sichtbar ist oder nicht"),
        System.ComponentModel.Category("GeoObject")]
        public bool ShowLabel
        {
            get
            {
                return showLabel;
            }
            set
            {
                showLabel = value;
            }
        }


        private bool isActive;
        /// <summary>
        /// Flag, das bestimmt, ob da Objekt zur Zeit selektiert ist
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public bool IsActive
        {
            get
            {
                return isActive;
            }
            set
            {
                isActive = value;
                if (value == true)
                    Parent.PropertyObject = this;
            }
        }

        private int m_Layer;
        /// <summary>
        /// Layer
        /// </summary
        [System.ComponentModel.Description("Legt ein Layer für Das GeoObject fest"),
        System.ComponentModel.Category("GeoObject")]
        public int Layer
        {
            get
            {
                return m_Layer;
            }
            set
            {
                m_Layer = value;
            }
        }




        private System.Windows.Forms.ContextMenu objectSpecificMenu;
        /// <summary>
        /// Kontextmenu des Objekts
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public System.Windows.Forms.ContextMenu ObjectSpecificMenu
        {
            get
            {
                return objectSpecificMenu;
            }
            set
            {
                objectSpecificMenu = value;
            }
        }

        private bool isMoving;
        /// <summary>
        /// Flag, das angibt, ob Objekt gerade bewegt wird
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public bool IsMoving
        {
            get
            {
                return isMoving;
            }
            set
            {
                isMoving = value;
            }
        }


        /// <summary>
        /// Punkt zum Verschieben des Objekts
        /// </summary>
        private Vector2D movePoint;
        [System.ComponentModel.Browsable(false)]
        public Vector2D MovePoint
        {
            get
            {
                return movePoint;

            }
            set
            {
                movePoint = value;

            }
        }

        private List<Vector2D> editPoints;
        /// <summary>
        /// Liste aus Vektoren zum Anzeigen des Objekts
        /// </summary>
        [System.ComponentModel.Category("GeoObject"),
        System.ComponentModel.DisplayName("Punkte"),
        System.ComponentModel.Description("Nur für Polygone und Polylines")]
        public List<Vector2D> EditPoints
        {
            get
            {
                return editPoints;
            }
            set
            {
                editPoints = value;
            }
        }

        /// <summary>
        /// Matrix um die der MovePoint verschoben wird
        /// </summary>
        private Matrix2D moveMatrix = Matrix2D.Identity;
        [System.ComponentModel.Browsable(false)]
        public Matrix2D MoveMatrix
        {
            get
            {
                return moveMatrix;
            }
            set
            {
                moveMatrix = value;
            }
        }

        private int currentPointToEditIndex;
        /// <summary>
        /// Aktueller Punkt, der editiert werden soll
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public int CurrentPointToEditIndex
        {
            get
            {
                return currentPointToEditIndex;
            }
            set
            {
                currentPointToEditIndex = value;
            }
        }
        /// <summary>
        /// Konstruktor
        /// </summary>
        public GeoObject()
        {
            DrawingPen = new Pen(Color.Black, 1);
            IsMoving = false;
            EditPoints = new List<Vector2D>();
            ObjectSpecificMenu = new System.Windows.Forms.ContextMenu();
            flashTimer.Tick += new EventHandler(t_Tick);
            CurrentPointToEditIndex = -1; //Kein Punkt ausgewählt
            //isActive = true;
        }




        /// <summary>
        /// Zeichnen eines Punktes auf das Control
        /// </summary>
        /// <param name="g">Graphics - Objekt</param>
        /// <param name="p">Punkt</param>
        /// <param name="c">Punktfarbe</param>
        /// <param name="isHit">Ausfüllen, falls wahr, ansonsten nur umranden</param>
        public void DrawPoint(Graphics g, Vector2D p, Color c, bool isHit)
        {
            if (!IsActive) return;
            Vector2D translatedPoint = p * Parent.TranslationScaleMatrix;
            if (isHit)
            {
                g.FillRectangle(new SolidBrush(c), (float)(translatedPoint.X - 3f * Parent.Zoom), (float)(translatedPoint.Y - 3f * Parent.Zoom), (float)(6f * Parent.Zoom), (float)(6f * Parent.Zoom));
            }
            else
            {
                g.DrawRectangle(new Pen(c, 2), (float)(translatedPoint.X - 3f * Parent.Zoom), (float)(translatedPoint.Y - 3f * Parent.Zoom), (float)(6f * Parent.Zoom), (float)(6f * Parent.Zoom));
            }
        }



        /// <summary>
        /// Zeichenstift
        /// </summary>
        private Pen drawingPen;
        [System.ComponentModel.Browsable(false)]
        public Pen DrawingPen
        {
            get
            {
                return drawingPen;
            }
            set
            {
                drawingPen = value;
            }
        }


        /// <summary>
        /// Farbe des Zeichenstifts
        /// </summary>
        [System.ComponentModel.Category("GeoObject"),
        System.ComponentModel.Description("Farbe des Zeichenstifts")]
        public Color DrawingColor
        {
            set
            {
                DrawingPen.Color = value;
            }
            get
            {
                return DrawingPen.Color;
            }
        }


        /// <summary>
        /// Dicke des Zeichenstifts
        /// </summary>
        [System.ComponentModel.Category("GeoObject"),
        System.ComponentModel.Description("Dicke des Zeichenstifts")]
        public float DrawingWidth
        {
            set
            {
                DrawingPen.Width = value;
            }
            get
            {
                return DrawingPen.Width;
            }
        }

        /// <summary>
        /// Elterncontainer
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public CADControl Parent
        {
            get;
            set;
        }


    }

    //////////////////////////////////////////////// Basisklasse - ENDE ////////////////////////////////////////////////










    //////////////////////////////////////////////////// Linie /////////////////////////////////////////////////////////
    /// <summary>
    /// Linie, abgeleitet von GeoObject
    /// </summary>
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class Line : GeoObject
    {
        public Line()
        {
            MovePoint = new Vector2D(0, 0);
        }

        /// <summary>
        /// Konstruktor mit zwei Punkten
        /// </summary>
        /// <param name="p1">Startpunkt</param>
        /// <param name="p2">Endpunkt</param>
        public Line(Vector2D p1, Vector2D p2)
        {

            EditPoints.Add(p1);
            EditPoints.Add(p2);
            MovePoint = new Vector2D((p1.X + p2.X) / 2.0, (p1.Y + p2.Y) / 2.0);

        }


        /// <summary>
        /// Methode zum Zeichnen von Linien
        /// </summary>
        /// <param name="g">Graphics - Object</param>
        /// <param name="translation">Verschiebung</param>
        public override void Draw(Graphics g)
        {
            MovePoint = new Vector2D((EditPoints[0].X + EditPoints[1].X) / 2.0, (EditPoints[0].Y + EditPoints[1].Y) / 2.0);

            //Sollen Layerfarben verwendet werden und ist Farbe für entsprechendes Layer verfügbar?
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                g.DrawLine(Parent.LayerColorTable[Layer], (Point)(EditPoints[0] * Parent.TranslationScaleMatrix), (Point)(EditPoints[1] * Parent.TranslationScaleMatrix));
            }
            else
            {
                g.DrawLine(DrawingPen, (Point)(EditPoints[0] * Parent.TranslationScaleMatrix), (Point)(EditPoints[1] * Parent.TranslationScaleMatrix));
            }

            //Layerfarben für Punkte verwenden? (s. oben)
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], Parent.LayerColorTable[Layer].Color.Complement(), i == CurrentPointToEditIndex);
                }
            }
            else
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], DrawingColor.Complement(), i == CurrentPointToEditIndex);
                }
            }

            DrawPoint(g, MovePoint, DrawingColor == Color.White ? Color.Red : Color.Black, IsMoving);

            base.Draw(g);
        }


        /// <summary>
        /// Methode zum Bewegen der Linie
        /// </summary>
        public override void Move()
        {
            MovePoint = MovePoint * MoveMatrix;
            EditPoints[0] *= MoveMatrix;
            EditPoints[1] *= MoveMatrix;
        }


        /// <summary>
        /// Methode zum Editiern eines Punktes
        /// </summary>
        /// <param name="pointToEdit">zu editierender Punkt</param>
        public override void Edit(int pointToEdit)
        {
            EditPoints[pointToEdit] *= MoveMatrix;
        }


        /// <summary>
        /// Methode zum Kopieren der gesamten Linie
        /// </summary>
        /// <returns>Linie</returns>
        public override GeoObject Clone()
        {
            Line l = new Line(this.EditPoints[0], this.EditPoints[1]);
            l.Parent = this.Parent;
            l.DrawingPen = (Pen)this.DrawingPen.Clone();
            l.MovePoint = this.MovePoint;
            l.IsActive = this.IsActive;
            l.Layer = this.Layer;
            l.DrawingColor = this.DrawingColor;
            l.DrawingWidth = this.DrawingWidth;
            l.MoveMatrix = this.MoveMatrix.Clone();
            return l;
        }
    }
    //////////////////////////////////////////////// Linie - ENDE ////////////////////////////////////////////////














    //////////////////////////////////////////////// Polyline ////////////////////////////////////////////////////
    /// <summary>
    /// Klasse für Polyline
    /// </summary>
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class PolyLine : GeoObject
    {

        /// <summary>
        /// Standardkonstruktor
        /// </summary>
        public PolyLine()
        {
            #region Kontextmenu
            System.Windows.Forms.MenuItem itmDeletePoint = new System.Windows.Forms.MenuItem("Punkt löschen", ((sender, e) =>
            {
                if (CurrentPointToEditIndex >= 0)
                {

                    if (EditPoints.Count <= 2)
                    {
                        System.Windows.Forms.MessageBox.Show("Polyline muss aus mehr als einem Punkt bestehen");
                    }
                    else
                    {
                        EditPoints.RemoveAt(CurrentPointToEditIndex);
                    }


                }
                CurrentPointToEditIndex = -1;
            }));

            System.Windows.Forms.MenuItem itmAddPoint = new System.Windows.Forms.MenuItem("Punkt hinzufügen", ((sender, e) =>
            {
                if (CurrentPointToEditIndex < EditPoints.Count - 1)
                {
                    EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D((EditPoints[CurrentPointToEditIndex + 1].X + EditPoints[CurrentPointToEditIndex].X) / 2.0, (EditPoints[CurrentPointToEditIndex + 1].Y + EditPoints[CurrentPointToEditIndex].Y) / 2.0));
                }
                else
                {
                    EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D(EditPoints[CurrentPointToEditIndex].X + 50, EditPoints[CurrentPointToEditIndex].Y + 50));
                }
                CurrentPointToEditIndex = -1;
            }));

            ObjectSpecificMenu.MenuItems.Add(itmDeletePoint);
            ObjectSpecificMenu.MenuItems.Add(itmAddPoint);
            #endregion
        }


        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="points">Punkte</param>
        public PolyLine(params Vector2D[] points)
        {

            #region Kontextmenu
            System.Windows.Forms.MenuItem itmDeletePoint = new System.Windows.Forms.MenuItem("Punkt löschen", ((sender, e) =>
            {
                if (CurrentPointToEditIndex >= 0)
                {

                    if (EditPoints.Count <= 2)
                    {
                        //System.Windows.Forms.MessageBox.Show("Polyline muss aus mehr als einem Punkt bestehen");
                        Parent.InfoText = "Polyline muss aus mehr als einem Punkt bestehen";
                    }
                    else
                    {
                        EditPoints.RemoveAt(CurrentPointToEditIndex);
                    }


                }
                CurrentPointToEditIndex = -1;
            }));

            System.Windows.Forms.MenuItem itmAddPoint = new System.Windows.Forms.MenuItem("Punkt hinzufügen", ((sender, e) =>
                {
                    if (CurrentPointToEditIndex < EditPoints.Count - 1)
                    {
                        EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D((EditPoints[CurrentPointToEditIndex + 1].X + EditPoints[CurrentPointToEditIndex].X) / 2.0, (EditPoints[CurrentPointToEditIndex + 1].Y + EditPoints[CurrentPointToEditIndex].Y) / 2.0));
                    }
                    else
                    {
                        EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D(EditPoints[CurrentPointToEditIndex].X + 50, EditPoints[CurrentPointToEditIndex].Y + 50));
                    }
                    CurrentPointToEditIndex = -1;
                }));

            ObjectSpecificMenu.MenuItems.Add(itmDeletePoint);
            ObjectSpecificMenu.MenuItems.Add(itmAddPoint);
            #endregion
            foreach (var point in points)
            {
                //geoPoints.Add(point);
                EditPoints.Add(point);
            }

            int index = (int)(EditPoints.Count / 2);

            MovePoint = new Vector2D((EditPoints[index].X + EditPoints[index + 1].X) / 2.0, (EditPoints[index].Y + EditPoints[index + 1].Y) / 2.0);
        }


        /// <summary>
        /// Methode zum Zeichnen der Polyline
        /// </summary>
        /// <param name="g">Graphics - Objekt</param>
        /// <param name="translation">Verschiebung</param>
        public override void Draw(Graphics g)
        {
            int index = (int)(EditPoints.Count / 2);
            MovePoint = new Vector2D((EditPoints[index - 1].X + EditPoints[index].X) / 2.0, (EditPoints[index - 1].Y + EditPoints[index].Y) / 2.0);


            //Sollen Layerfarben verwendet werden?
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                g.DrawLines(Parent.LayerColorTable[Layer], (from p in EditPoints
                                                            select
                                                            (PointF)(p * Parent.TranslationScaleMatrix)
                                         ).ToArray());
            }
            else
            {
                g.DrawLines(DrawingPen, (from p in EditPoints
                                         select
                                         (PointF)(p * Parent.TranslationScaleMatrix)
                                         ).ToArray());
            }


            //Entsprechend Layerfarben für die Punkte
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], Parent.LayerColorTable[Layer].Color.Complement(), i == CurrentPointToEditIndex);
                }
            }
            else
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], DrawingColor.Complement(), i == CurrentPointToEditIndex);
                }
            }

            //MovePoint zeichnen
            DrawPoint(g, MovePoint, DrawingColor == Color.White ? Color.Red : Color.Black, IsMoving);
            base.Draw(g);

        }

        /// <summary>
        /// Methode zum Bewegen der Polyline
        /// </summary>
        public override void Move()
        {
            base.Move();
            MovePoint = MovePoint * MoveMatrix;
            for (int i = 0; i < EditPoints.Count; i++)
            {
                EditPoints[i] = EditPoints[i] * MoveMatrix;
            }
        }

        /// <summary>
        /// Methode zum Editieren eines Punktes
        /// </summary>
        /// <param name="pointToEdit">zu editierender Punkt</param>
        public override void Edit(int pointToEdit)
        {
            EditPoints[pointToEdit] *= MoveMatrix;
        }


        /// <summary>
        /// Methode zum Kopieren der gesamten PolyLine
        /// </summary>
        /// <returns>PolyLine</returns>
        public override GeoObject Clone()
        {
            PolyLine l = new PolyLine(this.EditPoints.ToArray());
            l.Parent = this.Parent;
            l.DrawingPen = (Pen)this.DrawingPen.Clone();
            l.MovePoint = this.MovePoint;
            l.IsActive = this.IsActive;
            l.Layer = this.Layer;
            l.DrawingColor = this.DrawingColor;
            l.DrawingWidth = this.DrawingWidth;
            l.MoveMatrix = this.MoveMatrix.Clone();
            return l;
        }
    }
    //////////////////////////////////////////////// Polyline - ENDE ////////////////////////////////////////////////











    //////////////////////////////////////////////// Polygon ////////////////////////////////////////////////////////
    /// <summary>
    /// Polygon
    /// </summary>
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class Polygon : GeoObject
    {


        /// <summary>
        /// Standardkonstruktor
        /// </summary>
        public Polygon()
        {
            #region Kontextmenu
            System.Windows.Forms.MenuItem itmDeletePoint = new System.Windows.Forms.MenuItem("Punkt löschen", ((sender, e) =>
            {
                if (CurrentPointToEditIndex >= 0)
                {

                    if (EditPoints.Count <= 3)
                    {
                        //System.Windows.Forms.MessageBox.Show("Polygon muss aus mehr als zwei Punkten bestehen");
                        Parent.InfoText = "Polygon muss aus mehr als zwei Punkten bestehen";
                    }
                    else
                    {
                        EditPoints.RemoveAt(CurrentPointToEditIndex);
                    }

                    CurrentPointToEditIndex = -1;
                }
            }));

            System.Windows.Forms.MenuItem itmAddPoint = new System.Windows.Forms.MenuItem("Punkt hinzufügen", ((sender, e) =>
            {
                if (CurrentPointToEditIndex < EditPoints.Count - 1)
                {
                    EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D((EditPoints[CurrentPointToEditIndex + 1].X + EditPoints[CurrentPointToEditIndex].X) / 2.0, (EditPoints[CurrentPointToEditIndex + 1].Y + EditPoints[CurrentPointToEditIndex].Y) / 2.0));
                }
                else
                {
                    EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D(EditPoints[CurrentPointToEditIndex].X + 50, EditPoints[CurrentPointToEditIndex].Y + 50));
                }
                CurrentPointToEditIndex = -1;
            }));

            System.Windows.Forms.MenuItem itmCutPolygon = new System.Windows.Forms.MenuItem("Schneiden", ((sender, e) =>
                {
                    Parent.EditMode = CADControl.CADEditMode.Cut;
                }));

            ObjectSpecificMenu.MenuItems.Add(itmDeletePoint);
            ObjectSpecificMenu.MenuItems.Add(itmAddPoint);
            ObjectSpecificMenu.MenuItems.Add(itmCutPolygon);
            #endregion
        }


        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="points">Punkte</param>
        public Polygon(params Vector2D[] points)
        {
            try
            {
                #region Kontextmenu
                System.Windows.Forms.MenuItem itmDeletePoint = new System.Windows.Forms.MenuItem("Punkt löschen", ((sender, e) =>
                {
                    if (CurrentPointToEditIndex >= 0)
                    {

                        if (EditPoints.Count <= 3)
                        {
                            //System.Windows.Forms.MessageBox.Show("Polygon muss aus mehr als zwei Punkten bestehen");
                            Parent.InfoText = "Polygon muss aus mehr als zwei Punkten bestehen";
                        }
                        else
                        {
                            EditPoints.RemoveAt(CurrentPointToEditIndex);
                        }

                        CurrentPointToEditIndex = -1;
                    }
                }));

                System.Windows.Forms.MenuItem itmAddPoint = new System.Windows.Forms.MenuItem("Punkt hinzufügen", ((sender, e) =>
                {
                    if (CurrentPointToEditIndex < EditPoints.Count - 1)
                    {
                        EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D((EditPoints[CurrentPointToEditIndex + 1].X + EditPoints[CurrentPointToEditIndex].X) / 2.0, (EditPoints[CurrentPointToEditIndex + 1].Y + EditPoints[CurrentPointToEditIndex].Y) / 2.0));
                    }
                    else
                    {
                        EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D(EditPoints[CurrentPointToEditIndex].X + 50, EditPoints[CurrentPointToEditIndex].Y + 50));
                    }
                    CurrentPointToEditIndex = -1;
                }));

                System.Windows.Forms.MenuItem itmCutPolygon = new System.Windows.Forms.MenuItem("Schneiden", ((sender, e) =>
                {
                    Parent.EditMode = CADControl.CADEditMode.Cut;
                }));


                ObjectSpecificMenu.MenuItems.Add(itmDeletePoint);
                ObjectSpecificMenu.MenuItems.Add(itmAddPoint);
                ObjectSpecificMenu.MenuItems.Add(itmCutPolygon);
                #endregion

                foreach (var point in points)
                {
                    EditPoints.Add(point);
                }
                int index = (int)(EditPoints.Count / 2);
                MovePoint = new Vector2D((EditPoints[index].X + EditPoints[index + 1].X) / 2.0, (EditPoints[index].Y + EditPoints[index + 1].Y) / 2.0);
            }
            catch (System.Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }


        /// <summary>
        /// Methode zum Zeichnen des Polygons
        /// </summary>
        /// <param name="g">Graphics - Objekt</param>
        /// <param name="translation">Verschiebung</param>
        public override void Draw(Graphics g)
        {
            int index = (int)(EditPoints.Count / 2);
            
            MovePoint = new Vector2D((EditPoints[index - 1].X + EditPoints[index].X) / 2.0, (EditPoints[index - 1].Y + EditPoints[index].Y) / 2.0);


            //Layerfarben verwenden?
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer) && !Flash)
            {
                g.DrawPolygon(Parent.LayerColorTable[Layer], (from p in EditPoints
                                                              select
                                                              (PointF)(p * Parent.TranslationScaleMatrix)
                                           ).ToArray());
            }
            else
            {
                g.DrawPolygon(DrawingPen, (from p in EditPoints
                                           select
                                           (PointF)(p * Parent.TranslationScaleMatrix)
                                           ).ToArray());
            }

            //Layerfarbe für Punkte
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer) && !Flash)
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], Parent.LayerColorTable[Layer].Color.Complement(), i == CurrentPointToEditIndex);
                }
            }
            else
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], DrawingColor.Complement(), i == CurrentPointToEditIndex);
                }
            }

            DrawPoint(g, MovePoint, DrawingColor == Color.White ? Color.Red : Color.Black, IsMoving);


            base.Draw(g);
        }

        /// <summary>
        /// Methode zum Bewegen des Polygons
        /// </summary>
        public override void Move()
        {
            MovePoint = MovePoint * MoveMatrix;
            for (int i = 0; i < EditPoints.Count; i++)
            {
                EditPoints[i] = EditPoints[i] * MoveMatrix;
            }
        }


        /// <summary>
        /// Methode zum Editeren eines Punktes
        /// </summary>
        /// <param name="pointToEdit">zu editierender Punkt</param>
        public override void Edit(int pointToEdit)
        {
            EditPoints[pointToEdit] *= MoveMatrix;
        }


        /// <summary>
        /// Methode zum Kopieren des gesamten Polygons
        /// </summary>
        /// <returns>Polygon</returns>
        public override GeoObject Clone()
        {
            Polygon l = new Polygon(this.EditPoints.ToArray());
            l.Parent = this.Parent;
            l.DrawingPen = (Pen)this.DrawingPen.Clone();
            l.MovePoint = this.MovePoint;
            l.IsActive = this.IsActive;
            l.Layer = this.Layer;
            l.DrawingColor = this.DrawingColor;
            l.DrawingWidth = this.DrawingWidth;
            l.MoveMatrix = this.MoveMatrix.Clone();
            return l;
        }
    }
    //////////////////////////////////////////////// Polygon - ENDE ////////////////////////////////////////////////////////














    //////////////////////////////////////////////// MultiPolygon //////////////////////////////////////////////////////////
    /// <summary>
    /// MultiPolygon
    /// </summary>
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class MultiPolygon : Polygon
    {
        private Polygon[] polygons;
        /// <summary>
        /// Array der zu verwaltenden Polygone
        /// </summary>
        public Polygon[] Polygons
        {
            get
            {
                return polygons;
            }
            private set
            {
                polygons = value;
            }
        }


        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="polygons">Array der zu verwaltenden Polygone</param>
        /// <param name="vectors">Vektoren des umschließenden Multipolygons</param>
        public MultiPolygon(Polygon[] polygons, params Vector2D[] vectors)
            : base(vectors)
        {

            Polygons = polygons;

        }

        public MultiPolygon(Polygon[] polygons)
            :base()
        {
            Polygons = polygons;
        }

        public MultiPolygon()
            : base()
        {
        }
        /// <summary>
        /// Überladene Methode zum Bewegen des Multipolygons sowie der eingeschlossenen Polygone
        /// </summary>
        public override void Move()
        {
            foreach (Polygon p in Polygons)
            {
                if (p != null)
                {
                    for (int i = 0; i < p.EditPoints.Count; i++)
                    {
                        p.EditPoints[i] *= MoveMatrix;
                    }
                }
            }
            base.Move();
            Parent.Invalidate(true);
        }

        /// <summary>
        /// Kopier - Methode zum Klonen des Multipolygons
        /// </summary>
        /// <returns>MultiPolygon</returns>
        public override GeoObject Clone()
        {
            MultiPolygon p = new MultiPolygon(Polygons, this.EditPoints.ToArray());
            p.Parent = this.Parent;
            p.DrawingPen = (Pen)this.DrawingPen.Clone();
            p.MovePoint = this.MovePoint;
            p.IsActive = this.IsActive;
            p.Layer = this.Layer;
            p.DrawingColor = this.DrawingColor;
            p.DrawingWidth = this.DrawingWidth;
            p.MoveMatrix = this.MoveMatrix.Clone();
            return p;
        }

    }
    ////////////////////////////////////////////// Multipolygon - ENDE /////////////////////////////////////////////////////






    #region MultiPolygon - DEPRECATED
    //////////////////////////////////// MultiPolygon - DEPRECATED /////////////////////////////////////////////////////////
    /// <summary>
    /// MultiPolygon
    /// </summary>
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //public class MultiPolygon : GeoObject
    //{
    //    List<Polygon> polygons = new List<GeoObjects.Polygon>();
    //    public List<Polygon> Polygons
    //    {
    //        get
    //        {
    //            return polygons;
    //        }
    //    }



    //    public struct PolygonPoint
    //    {
    //        public int PointNumber;
    //        public Polygon Polygon;
    //    }
    //    Dictionary<int, PolygonPoint> pointMapper = new Dictionary<int, PolygonPoint>();
    //    /// <summary>
    //    /// Standardkonstruktor
    //    /// </summary>
    //    public MultiPolygon()
    //    {



    //        #region Kontextmenu
    //        System.Windows.Forms.MenuItem itmDeletePoint = new System.Windows.Forms.MenuItem("Punkt löschen", ((sender, e) =>
    //        {
    //            if (CurrentPointToEditIndex >= 0)
    //            {

    //                if (pointMapper[CurrentPointToEditIndex].Polygon.EditPoints.Count <= 3)
    //                {
    //                    //System.Windows.Forms.MessageBox.Show("Polygon muss aus mehr als zwei Punkten bestehen");
    //                    Parent.InfoText = "Polygon muss aus mehr als zwei Punkten bestehen";
    //                }
    //                else
    //                {
    //                    EditPoints.RemoveAt(CurrentPointToEditIndex);
    //                    //TODO: Multipolygon...geht so noch nicht
    //                    pointMapper[CurrentPointToEditIndex].Polygon.EditPoints.RemoveAt(pointMapper[CurrentPointToEditIndex].PointNumber);
    //                    Parent.Invalidate(true);
    //                }

    //                CurrentPointToEditIndex = -1;
    //            }
    //        }));

    //        System.Windows.Forms.MenuItem itmAddPoint = new System.Windows.Forms.MenuItem("Punkt hinzufügen", ((sender, e) =>
    //        {
    //            if (CurrentPointToEditIndex < EditPoints.Count - 1)
    //            {
    //                EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D((EditPoints[CurrentPointToEditIndex + 1].X + EditPoints[CurrentPointToEditIndex].X) / 2.0, (EditPoints[CurrentPointToEditIndex + 1].Y + EditPoints[CurrentPointToEditIndex].Y) / 2.0));
    //                //pointMapper[CurrentPointToEditIndex].Polygon.EditPoints.Insert(CurrentPointToEditIndex + 1,
    //                //    new Vector2D((pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[CurrentPointToEditIndex + 1].X + pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[CurrentPointToEditIndex].X) / 2.0, (pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[CurrentPointToEditIndex + 1].Y + pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[CurrentPointToEditIndex].Y) / 2.0));

    //            }
    //            else
    //            {
    //                EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D(EditPoints[CurrentPointToEditIndex].X + 50, EditPoints[CurrentPointToEditIndex].Y + 50));
    //                //pointMapper[CurrentPointToEditIndex].Polygon.EditPoints.Insert(CurrentPointToEditIndex + 1,
    //                //    new Vector2D(pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[CurrentPointToEditIndex].X + 50, pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[CurrentPointToEditIndex + 1].Y + 50));
    //            }
    //            CurrentPointToEditIndex = -1;
    //        }));

    //        System.Windows.Forms.MenuItem itmCutPolygon = new System.Windows.Forms.MenuItem("Schneiden", ((sender, e) =>
    //        {
    //            Parent.EditMode = CADControl.CADEditMode.Cut;
    //        }));

    //        ObjectSpecificMenu.MenuItems.Add(itmDeletePoint);
    //        ObjectSpecificMenu.MenuItems.Add(itmAddPoint);
    //        ObjectSpecificMenu.MenuItems.Add(itmCutPolygon);
    //        #endregion


    //    }


    //    /// <summary>
    //    /// Konstruktor
    //    /// </summary>
    //    /// <param name="polys">Polygone</param>
    //    public MultiPolygon(params Polygon[] polys)
    //    {
    //        #region Kontextmenu
    //        System.Windows.Forms.MenuItem itmDeletePoint = new System.Windows.Forms.MenuItem("Punkt löschen", ((sender, e) =>
    //        {
    //            if (CurrentPointToEditIndex >= 0)
    //            {

    //                if (pointMapper[CurrentPointToEditIndex].Polygon.EditPoints.Count <= 3)
    //                {
    //                    //System.Windows.Forms.MessageBox.Show("Polygon muss aus mehr als zwei Punkten bestehen");
    //                    Parent.InfoText = "Polygon muss aus mehr als zwei Punkten bestehen";
    //                }
    //                else
    //                {
    //                    EditPoints.RemoveAt(CurrentPointToEditIndex);
    //                    pointMapper[CurrentPointToEditIndex].Polygon.EditPoints.RemoveAt(pointMapper[CurrentPointToEditIndex].PointNumber);
    //                    Parent.Invalidate(true);
    //                }

    //                CurrentPointToEditIndex = -1;
    //            }
    //        }));

    //        System.Windows.Forms.MenuItem itmAddPoint = new System.Windows.Forms.MenuItem("Punkt hinzufügen", ((sender, e) =>
    //        {
    //            if (CurrentPointToEditIndex < EditPoints.Count - 1)
    //            {
    //                EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D((EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber + 1].X + EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber].X) / 2.0, (EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber + 1].Y + EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber].Y) / 2.0));
    //                pointMapper.Add(pointMapper.Count, pointMapper[CurrentPointToEditIndex + 1]);
    //                pointMapper[CurrentPointToEditIndex + 1] = new PolygonPoint() { PointNumber = pointMapper[CurrentPointToEditIndex].PointNumber + 1, Polygon = pointMapper[CurrentPointToEditIndex].Polygon };


    //                //.Polygon.EditPoints.Insert(pointMapper[CurrentPointToEditIndex].PointNumber + 1,
    //                //new Vector2D((pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber + 1].X + pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber].X) / 2.0, (pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber + 1].Y + pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber].Y) / 2.0));
    //                Parent.Invalidate(true);
    //            }
    //            else
    //            {
    //                EditPoints.Insert(CurrentPointToEditIndex + 1, new Vector2D(EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber].X + 50, EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber].Y + 50));
    //                pointMapper.Add(CurrentPointToEditIndex + 1, new PolygonPoint() { PointNumber = pointMapper[CurrentPointToEditIndex].PointNumber + 1, Polygon = pointMapper[CurrentPointToEditIndex].Polygon });
    //                pointMapper[CurrentPointToEditIndex + 1].Polygon.EditPoints.Insert(pointMapper[CurrentPointToEditIndex].PointNumber + 1,
    //                    new Vector2D(pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber].X + 50, pointMapper[CurrentPointToEditIndex].Polygon.EditPoints[pointMapper[CurrentPointToEditIndex].PointNumber + 1].Y + 50));
    //                Parent.Invalidate(true);
    //            }
    //            CurrentPointToEditIndex = -1;
    //        }));

    //        System.Windows.Forms.MenuItem itmCutPolygon = new System.Windows.Forms.MenuItem("Schneiden", ((sender, e) =>
    //        {
    //            Parent.EditMode = CADControl.CADEditMode.Cut;
    //        }));


    //        ObjectSpecificMenu.MenuItems.Add(itmDeletePoint);
    //        ObjectSpecificMenu.MenuItems.Add(itmAddPoint);
    //        ObjectSpecificMenu.MenuItems.Add(itmCutPolygon);
    //        #endregion

    //        polygons = polys.ToList<Polygon>();
    //        foreach (var polygon in polygons)
    //        {
    //            int j = 0;
    //            foreach (var point in polygon.EditPoints)
    //            {
    //                EditPoints.Add(point);
    //                pointMapper.Add(EditPoints.Count - 1, new PolygonPoint() { PointNumber = j++, Polygon = polygon });
    //            }
    //        }
    //        int index = (int)(polygons[0].EditPoints.Count / 2);
    //        MovePoint = new Vector2D((polygons[0].EditPoints[index].X + polygons[0].EditPoints[index + 1].X) / 2.0, (polygons[0].EditPoints[index].Y + polygons[0].EditPoints[index + 1].Y) / 2.0);
    //    }


    //    /// <summary>
    //    /// Methode zum Zeichnen der Polygone
    //    /// </summary>
    //    /// <param name="g">Graphics - Objekt</param>
    //    /// <param name="translation">Verschiebung</param>
    //    public override void Draw(Graphics g)
    //    {
    //        int index = (int)(polygons[0].EditPoints.Count / 2);

    //        MovePoint = new Vector2D((polygons[0].EditPoints[index - 1].X + polygons[0].EditPoints[index].X) / 2.0, (polygons[0].EditPoints[index - 1].Y + polygons[0].EditPoints[index].Y) / 2.0);
    //        foreach (var poly in polygons)
    //        {
    //            g.DrawPolygon(DrawingPen, (from p in poly.EditPoints
    //                                       select
    //                                       (PointF)(p * Parent.TranslationScaleMatrix)
    //                                       ).ToArray());

    //            for (int i = 0; i < poly.EditPoints.Count; i++)
    //            {
    //                DrawPoint(g, poly.EditPoints[i], DrawingColor.Complement(), i == CurrentPointToEditIndex);
    //            }
    //        }
    //        DrawPoint(g, MovePoint, DrawingColor == Color.White ? Color.Red : Color.Black, IsMoving);

    //        base.Draw(g);
    //    }


    //    public override void Move()
    //    {
    //        MovePoint = MovePoint * MoveMatrix;
    //        int j = 0;
    //        foreach (var poly in polygons)
    //        {
    //            for (int i = 0; i < poly.EditPoints.Count; i++)
    //            {
    //                poly.EditPoints[i] = poly.EditPoints[i] * MoveMatrix;
    //                EditPoints[j++] *= MoveMatrix;
    //            }
    //        }


    //    }

    //    public override void Edit(int pointToEdit)
    //    {
    //        pointMapper[pointToEdit].Polygon.EditPoints[pointMapper[pointToEdit].PointNumber] *= MoveMatrix;
    //        //polygons.Select(s => s.EditPoints).Where(w => w.Contains(EditPoints[pointToEdit])).First()[pointToEdit] *= MoveMatrix;
    //        EditPoints[pointToEdit] *= MoveMatrix;
    //    }

    //    public override GeoObject Clone()
    //    {
    //        MultiPolygon multiPolygon = new MultiPolygon(this.Polygons.ToArray());
    //        multiPolygon.Parent = this.Parent;
    //        multiPolygon.DrawingPen = (Pen)this.DrawingPen.Clone();
    //        multiPolygon.MovePoint = this.MovePoint;
    //        multiPolygon.IsActive = this.IsActive;
    //        multiPolygon.layer = this.layer;
    //        multiPolygon.DrawingColor = this.DrawingColor;
    //        multiPolygon.DrawingWidth = this.DrawingWidth;
    //        multiPolygon.MoveMatrix = this.MoveMatrix.Clone();
    //        return multiPolygon;
    //    }
    //}
    //////////////////////////////////////////// Multipolygon - ENDE ///////////////////////////////////////////////
    #endregion







    //////////////////////////////////////////////// Ellipse ////////////////////////////////////////////////////////
    /// <summary>
    /// Ellipse
    /// </summary>
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class Ellipse : GeoObject
    {
        private double width;
        /// <summary>
        /// Breite der Ellipse
        /// </summary>
        [System.ComponentModel.Category("GeoObject"),
        System.ComponentModel.Description("Breite der Ellipse")]
        public double Width
        {
            get
            {
                return width;
            }
            set
            {
                width = value;
                EditPoints[0] = new Vector2D(MovePoint.X + (width * 0.5), MovePoint.Y);
            }
        }

        private double height;
        /// <summary>
        /// Höhe der Ellipse
        /// </summary>
        [System.ComponentModel.Category("GeoObject"),
        System.ComponentModel.Description("Höhe der Ellipse")]
        public double Height
        {
            get
            {
                return height;
            }
            set
            {
                height = value;
                EditPoints[1] = new Vector2D(MovePoint.X, MovePoint.Y + (height * 0.5));
            }
        }


        /// <summary>
        /// Standardkonstruktor
        /// </summary>
        public Ellipse()
        {
            MovePoint = new Vector2D(0, 0);
            EditPoints = new List<Vector2D>();
        }


        /// <summary>
        /// Konstruktor mit Mittelpunkt, Breite und Höhe
        /// </summary>
        /// <param name="centerPoint">Mittelpunkt</param>
        /// <param name="ellipseWidth">Breite</param>
        /// <param name="ellipseHeight">Höhe</param>
        public Ellipse(Vector2D centerPoint, double ellipseWidth, double ellipseHeight)
        {
            MovePoint = centerPoint;

            EditPoints.Add(new Vector2D(MovePoint.X + (ellipseWidth * 0.5), MovePoint.Y)); //Point 0 => Width
            EditPoints.Add(new Vector2D(MovePoint.X, MovePoint.Y + (ellipseHeight * 0.5))); //Point 1 => Height
            Width = ellipseWidth;
            Height = ellipseHeight;
        }


        /// <summary>
        /// Methode zum Zeichnen der Ellipse
        /// </summary>
        /// <param name="g">Graphics - Objekt, auf dem gezeichnet wird</param>
        public override void Draw(Graphics g)
        {
            //Layerfarben verwenden?
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                g.DrawEllipse(Parent.LayerColorTable[Layer],
                    (float)((MovePoint * Parent.TranslationScaleMatrix).X - ((float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2) / 2f),
                    (float)((MovePoint * Parent.TranslationScaleMatrix).Y - ((float)(EditPoints[1].Y - MovePoint.Y) * (float)Parent.Zoom * 2) / 2f),
                    (float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2,
                    (float)(EditPoints[1].Y - MovePoint.Y) * (float)Parent.Zoom * 2);
            }
            else
            {
                g.DrawEllipse(DrawingPen,
                   (float)((MovePoint * Parent.TranslationScaleMatrix).X - ((float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2) / 2f),
                   (float)((MovePoint * Parent.TranslationScaleMatrix).Y - ((float)(EditPoints[1].Y - MovePoint.Y) * (float)Parent.Zoom * 2) / 2f),
                   (float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2,
                   (float)(EditPoints[1].Y - MovePoint.Y) * (float)Parent.Zoom * 2);
            }


            DrawPoint(g, MovePoint, DrawingColor == Color.White ? Color.Red : Color.Black, IsMoving);

            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], Parent.LayerColorTable[Layer].Color.Complement(), i == CurrentPointToEditIndex);
                }
            }
            else
            {
                for (int i = 0; i < EditPoints.Count; i++)
                {
                    DrawPoint(g, EditPoints[i], DrawingColor.Complement(), i == CurrentPointToEditIndex);
                }
            }
            base.Draw(g);
        }


        /// <summary>
        /// Methode zum Bewegen der Ellipse
        /// </summary>
        public override void Move()
        {
            MovePoint *= MoveMatrix;
            for (int i = 0; i < EditPoints.Count; i++)
            {
                EditPoints[i] = EditPoints[i] * MoveMatrix;
            }
        }



        /// <summary>
        /// Methode zum Editieren des Punktes
        /// </summary>
        /// <param name="pointToEdit">zu editierender Punkt</param>
        public override void Edit(int pointToEdit)
        {

            if (pointToEdit == 0) //Breite wird verändert
            {
                double tmpY = EditPoints[0].Y;
                EditPoints[0] *= MoveMatrix;
                EditPoints[0].Y = tmpY;
                //Breite kann nicht negativ werden
                //Width = Math.Abs(EditPoints[0].X - MovePoint.X) * 2; 
                // Breite kann negativ werden, Ellipse wird dann gespiegelt
                Width = (EditPoints[0].X - MovePoint.X) * 2;
            }
            else if (pointToEdit == 1) //Höhe wird verändert
            {
                double tmpX = EditPoints[1].X;
                EditPoints[1] *= MoveMatrix;
                EditPoints[1].X = tmpX;
                //Höhe kann nicht negativ werden
                //Height = Math.Abs(EditPoints[1].Y - MovePoint.Y) * 2;
                // Höhe kann negativ werden, Ellipse wird dann gespiegelt
                Height = (EditPoints[1].Y - MovePoint.Y) * 2;
            }
        }


        /// <summary>
        /// Methode zum Kopieren der gesamten Ellipse
        /// </summary>
        /// <returns>Ellipse</returns>
        public override GeoObject Clone()
        {
            Ellipse el = new Ellipse(new Vector2D(MovePoint.X, MovePoint.Y), this.Width, this.Height);
            el.Parent = this.Parent;
            el.DrawingPen = (Pen)this.DrawingPen.Clone();
            el.MovePoint = this.MovePoint;
            el.IsActive = this.IsActive;
            el.Layer = this.Layer;
            el.DrawingColor = this.DrawingColor;
            el.DrawingWidth = this.DrawingWidth;
            el.MoveMatrix = this.MoveMatrix.Clone();
            return el;
        }
    }
    ///////////////////////////////////////////// Ellipse - ENDE /////////////////////////////////////////////////////











    //////////////////////////////////////////////// Kreis //////////////////////////////////////////////////////////
    /// <summary>
    /// Kreis
    /// </summary>
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class Circle : GeoObject
    {
        private double radius;
        /// <summary>
        /// Radius des Kreises
        /// </summary>
        [System.ComponentModel.Category("GeoObject"),
        System.ComponentModel.Description("Radius des Kreises")]
        public double Radius
        {
            get
            {
                return radius;
            }
            set
            {
                radius = value;
                EditPoints[0] = new Vector2D(MovePoint.X + (radius * 0.5), MovePoint.Y);
                //EditPoints[1] = new Vector2D(MovePoint.X + (Radius * 0.5), MovePoint.Y);
            }
        }

        /// <summary>
        /// Standardkonstruktor
        /// </summary>
        public Circle()
        {
            MovePoint = new Vector2D(0, 0);
            EditPoints = new List<Vector2D>();
            #region Kontextmenu
            System.Windows.Forms.MenuItem itmConvertToEllipse = new System.Windows.Forms.MenuItem("Zur Ellipse konvertieren", ((sender, e) =>
            {
                Ellipse el = new Ellipse(MovePoint, Radius, Radius);
                el.DrawingPen = this.DrawingPen;
                el.Parent = this.Parent;
                el.MoveMatrix = this.MoveMatrix;
                Parent.Add(el);
                Parent.GeoObjects.Remove(this);
            }));
            ObjectSpecificMenu.MenuItems.Add(itmConvertToEllipse);
            #endregion
        }


        /// <summary>
        /// Konstruktor mit Mitte und Raduis
        /// </summary>
        /// <param name="centerPoint">Mittelpunkt</param>
        /// <param name="circleRadius">Radius</param>
        public Circle(Vector2D centerPoint, double circleRadius)
        {
            EditPoints = new List<Vector2D>();
            MovePoint = centerPoint;
            EditPoints.Add(new Vector2D(MovePoint.X + (Radius * 0.5), MovePoint.Y));

            Radius = circleRadius;

            #region Kontextmenu
            System.Windows.Forms.MenuItem itmConvertToEllipse = new System.Windows.Forms.MenuItem("Zur Ellipse konvertieren", ((sender, e) =>
            {
                Ellipse el = new Ellipse(MovePoint, Radius, Radius);
                el.DrawingPen = this.DrawingPen;
                el.Parent = this.Parent;
                el.MoveMatrix = this.MoveMatrix;
                Parent.Add(el);
                Parent.GeoObjects.Remove(this);
            }));
            ObjectSpecificMenu.MenuItems.Add(itmConvertToEllipse);
            #endregion
        }



        /// <summary>
        /// Methode zum Zeichnen des Kreises
        /// </summary>
        /// <param name="g">Graphics - Objekt, auf dem gezeichnet wird</param>
        public override void Draw(Graphics g)
        {
            //Layerfarben verwenden?
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                g.DrawEllipse(Parent.LayerColorTable[Layer],
                    (float)((MovePoint * Parent.TranslationScaleMatrix).X - ((float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2) / 2f),
                    (float)((MovePoint * Parent.TranslationScaleMatrix).Y - ((float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2) / 2f),
                    (float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2,
                    (float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2);
            }
            else
            {
                g.DrawEllipse(DrawingPen,
                    (float)((MovePoint * Parent.TranslationScaleMatrix).X - ((float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2) / 2f),
                    (float)((MovePoint * Parent.TranslationScaleMatrix).Y - ((float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2) / 2f),
                    (float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2,
                    (float)(EditPoints[0].X - MovePoint.X) * (float)Parent.Zoom * 2);
            }

            //MovePoint zeichnen
            DrawPoint(g, MovePoint, DrawingColor == Color.White ? Color.Red : Color.Black, IsMoving);

            //Layerfarben für Punkte
            if (Parent.UseLayerColors && Parent.LayerColorTable.Keys.Contains(Layer))
            {
                DrawPoint(g, EditPoints[0], Parent.LayerColorTable[Layer].Color.Complement(), 0 == CurrentPointToEditIndex);
            }
            else
            {
                DrawPoint(g, EditPoints[0], DrawingColor.Complement(), 0 == CurrentPointToEditIndex);
            }
            base.Draw(g);
        }


        /// <summary>
        /// Methode zum Bewegen des Kreises
        /// </summary>
        public override void Move()
        {
            MovePoint *= MoveMatrix;
            EditPoints[0] *= MoveMatrix;
        }

        /// <summary>
        /// Methode zum Editieren eines Punktes
        /// </summary>
        /// <param name="pointToEdit">zu editierender Punkt</param>
        public override void Edit(int pointToEdit)
        {
            double tmpY = EditPoints[0].Y;
            EditPoints[0] = EditPoints[0] * MoveMatrix;
            EditPoints[0].Y = tmpY;
            //Radius kann nicht negativ werden:
            //Radius = Math.Abs(EditPoints[0].X - MovePoint.X) * 2;
            // Radius kann negativ werden, Kreis wird dann gespiegelt:
            Radius = (EditPoints[0].X - MovePoint.X) * 2;
        }


        /// <summary>
        /// Methode zum Kopieren des gesamten Kreises
        /// </summary>
        /// <returns>Kreis</returns>
        public override GeoObject Clone()
        {
            Circle c = new Circle(new Vector2D(MovePoint.X, MovePoint.Y), this.Radius);
            c.Parent = this.Parent;
            c.DrawingPen = (Pen)this.DrawingPen.Clone();
            c.MovePoint = this.MovePoint;
            c.IsActive = this.IsActive;
            c.Layer = this.Layer;
            c.DrawingColor = this.DrawingColor;
            c.DrawingWidth = this.DrawingWidth;
            c.MoveMatrix = this.MoveMatrix.Clone();
            return c;

        }
    }
    ///////////////////////////////////////////// Kreis - ENDE /////////////////////////////////////////////////////









    ///////////////////////////////////////////// Erweiterungen /////////////////////////////////////////////////////
    /// <summary>
    /// Erweiterungsklasse
    /// </summary>
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public static class ExtensionClass
    {
        public static Color Complement(this Color color)
        {
            return Color.FromArgb(255 - color.R, 255 - color.G, 255 - color.B);
        }
    }
    //////////////////////////////////////// Erweiterungen - ENDE //////////////////////////////////////////////////


}
